package com.sealer.utils;

import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by sealer on 17/04/12.
 */
public class ArithmeticUtil {
    /**
     * reverse polish notation
     * 转为逆波兰式
     * 返回的是逆波兰式的栈
     */
    private static Stack toRpn(String expression) {
        //存放操作符的栈
        Stack<Character> operStack = new Stack<>();
        //存放后缀表达式的栈, 顺序是从栈底数， 第一个位置是第一个操作数
        Stack<Object> rpnStackReverse = new Stack<>();

        int length = expression.length();
        char c1;
        for (int i = 0; i < length; i++) {
            c1 = expression.charAt(i);
            if (isOperator(c1)) {//如果是操作符
                if (operStack.empty()) {
                    operStack.push(c1);
                } else {
                    //c1为操作符且优先级比operStack栈顶操作符优先级高时，直接把操作符压入s1
                    if (priorityCompare(c1, operStack.peek()) == 1) {
                        operStack.push(c1);
                    } else {//c1为操作符且优先级比operStack栈顶操作符优先级低时， 弹出operStack栈顶的操作符并压入rpnStack，直到c1优先级小于operStack栈顶的操作符优先级
                        while (!operStack.isEmpty() && priorityCompare(c1, operStack.peek()) != 1) {
                            rpnStackReverse.push(operStack.pop());
                        }
                        operStack.push(c1);//这里当时写错了， 查了好半天。写成了rpnStackReverse
                    }
                }

            } else {//若操作数为数字，直接压入rpnStackReverse
                rpnStackReverse.push(c1);
            }
        }
        //把operStack中剩余的元素压入rpnStackReverse中, 当时这段逻辑没写
        while (!operStack.isEmpty()) {
            rpnStackReverse.push(operStack.pop());
        }
        Stack<Object> rpnStack = new Stack<>();//栈顶元素是逆波兰式表达式的第一个操作数, 此时栈顶元素相当于用数组存放的首个元素
        while (!rpnStackReverse.isEmpty()) {
            rpnStack.push(rpnStackReverse.pop());
        }
        return rpnStack;
    }

    /**
     * 判断是否是操作符
     *
     * @param o
     * @return
     */

    /**
     * 多位正整数的运算
     *
     * @param expression
     * @return
     */
    private static Stack toRpn2(String expression) {
        //存放操作符的栈
        Stack<Character> operStack = new Stack<>();
        //存放后缀表达式的栈, 顺序是从栈底数， 第一个位置是第一个操作数
        Stack<Object> rpnStackReverse = new Stack<>();
        String[] opers = expression.split("\\d+");
        String[] nums = expression.split("[+|\\-|*|/]");
        int length = opers.length + nums.length - 1;
        System.out.println(opers.length + "===" + nums.length + "===" + length);
        String[] expressions = new String[length];
        for (int i = 0, j = 0; j < nums.length - 1; i += 2, j++) {
            expressions[i] = nums[j].trim();
            expressions[i + 1] = opers[j + 1].trim();
        }
        expressions[length - 1] = nums[nums.length - 1];

        String c1;
        for (int i = 0; i < length; i++) {
            c1 = expressions[i];
            char c = c1.charAt(0);
            if (isOperator(c)) {//如果是操作符

                if (operStack.empty()) {
                    operStack.push(c);
                } else {
                    //c1为操作符且优先级比operStack栈顶操作符优先级高时，直接把操作符压入s1
                    if (priorityCompare(c, operStack.peek()) == 1) {
                        operStack.push(c);
                    } else {//c1为操作符且优先级比operStack栈顶操作符优先级低时， 弹出operStack栈顶的操作符并压入rpnStack，直到c1优先级小于operStack栈顶的操作符优先级
                        while (!operStack.isEmpty() && priorityCompare(c, operStack.peek()) != 1) {
                            rpnStackReverse.push(operStack.pop());
                        }
                        operStack.push(c);//这里当时写错了， 查了好半天。写成了rpnStackReverse
                    }
                }

            } else {//若操作数为数字，直接压入rpnStackReverse
                rpnStackReverse.push(c1);
            }
        }
        //把operStack中剩余的元素压入rpnStackReverse中, 当时这段逻辑没写
        while (!operStack.isEmpty()) {
            rpnStackReverse.push(operStack.pop());
        }
        Stack<Object> rpnStack = new Stack<>();//栈顶元素是逆波兰式表达式的第一个操作数, 此时栈顶元素相当于用数组存放的首个元素
        while (!rpnStackReverse.isEmpty()) {
            rpnStack.push(rpnStackReverse.pop());
        }
        return rpnStack;
    }

    private static boolean isOperator(Object o) {
        /*if (o instanceof String) {
            return false;
        }*/
        System.out.println("+++++++++++++++++++o instanceof Character:" + (o instanceof Character));
        char c1 = (char) o;
        if (c1 == '+' || c1 == '-' || c1 == '*' || c1 == '/') {
            return true;
        } else {
            return false;
        }
    }


    /**
     * double多位数操作
     * @param expression
     * @return
     */
    private static Stack toRpn3(String expression) {
        //存放操作符的栈
        Stack<Character> operStack = new Stack<>();
        //存放后缀表达式的栈, 顺序是从栈底数， 第一个位置是第一个操作数
        Stack<Object> rpnStackReverse = new Stack<>();
        String[] opers = expression.split("\\d+(\\.\\d+)?");//double
        String[] nums = expression.split("[+|\\-|*|/]");
        int length = opers.length + nums.length - 1;
        System.out.println(opers.length + "===" + nums.length + "===" + length);
        String[] expressions = new String[length];
        for (int i = 0, j = 0; j < nums.length - 1; i += 2, j++) {
            expressions[i] = nums[j].trim();
            expressions[i + 1] = opers[j + 1].trim();
        }
        expressions[length - 1] = nums[nums.length - 1];

        String c1;
        for (int i = 0; i < length; i++) {
            c1 = expressions[i];
            char c = c1.charAt(0);
            if (isOperator(c)) {//如果是操作符

                if (operStack.empty()) {
                    operStack.push(c);
                } else {
                    //c1为操作符且优先级比operStack栈顶操作符优先级高时，直接把操作符压入s1
                    if (priorityCompare(c, operStack.peek()) == 1) {
                        operStack.push(c);
                    } else {//c1为操作符且优先级比operStack栈顶操作符优先级低时， 弹出operStack栈顶的操作符并压入rpnStack，直到c1优先级小于operStack栈顶的操作符优先级
                        while (!operStack.isEmpty() && priorityCompare(c, operStack.peek()) != 1) {
                            rpnStackReverse.push(operStack.pop());
                        }
                        operStack.push(c);//这里当时写错了， 查了好半天。写成了rpnStackReverse
                    }
                }

            } else {//若操作数为数字，直接压入rpnStackReverse
                rpnStackReverse.push(c1);
            }
        }
        //把operStack中剩余的元素压入rpnStackReverse中, 当时这段逻辑没写
        while (!operStack.isEmpty()) {
            rpnStackReverse.push(operStack.pop());
        }
        Stack<Object> rpnStack = new Stack<>();//栈顶元素是逆波兰式表达式的第一个操作数, 此时栈顶元素相当于用数组存放的首个元素
        while (!rpnStackReverse.isEmpty()) {
            rpnStack.push(rpnStackReverse.pop());
        }
        return rpnStack;
    }


    /**
     * 判断操作符的优先级
     */
    private static int priorityCompare(char c1, char c2) {
        int result = 1;
        switch (c1) {
            case '+':
            case '-':
                result = (c2 == '*' || c2 == '/' ? -1 : 0);
                break;
            case '*':
            case '/':
                result = (c2 == '+' || c2 == '-' ? 1 : 0);
                break;
        }

        return result;
    }

    /**
     * calculate 计算
     */
    private static double calculate(double x, double y, char z) {
        double result = 0.0;
        switch (z) {
            case '+':
                result = x + y;
                break;
            case '-':
                result = x - y;
                break;
            case '*':
                result = x * y;
                break;
            case '/':
                result = x / y;
                break;
        }
        return result;
    }

    //一位正整数
    private static boolean isVerified(String expression) {
        Pattern pattern = Pattern.compile("\\d([+|\\-|*|/]\\d)*");
        Matcher matcher = pattern.matcher(expression);
        return matcher.matches();
    }

    //多位正整数
    private static boolean isVerified2(String expression) {
        Pattern pattern = Pattern.compile("\\d+([+|\\-|*|/]\\d+)*");
        Matcher matcher = pattern.matcher(expression);
        return matcher.matches();
    }

    //double
    private static boolean isVerified3(String expression) {
        Pattern pattern = Pattern.compile("\\d+(\\.\\d+)?([+|\\-|*|/]\\d+(\\.\\d+)?)*");
        Matcher matcher = pattern.matcher(expression);
        return matcher.matches();
    }


    /**
     * 一位正整数运算
     * @param expression
     * @return
     * @throws Exception
     */
    public static double getResult(String expression) throws Exception {
        if (!isVerified(expression)) {
            throw new Exception("参数错误， 不是合法的表达式。");
        }
        //逆波兰表达式栈， 栈顶是第一个操作数
        Stack<Object> rpnStack = toRpn2(expression);
        //计算结果用临时栈
        Stack<Double> tmpStack = new Stack<>();

        while (!rpnStack.empty()) {
            if (rpnStack.peek() instanceof String) {//这个判断真费时间了。。。
                tmpStack.push(Double.parseDouble(rpnStack.pop().toString()));
            } else {
                Double second = tmpStack.pop();//先弹栈的是第二操作数
                Double first = tmpStack.pop();
                Double result = calculate(first, second, (char) rpnStack.pop());
                tmpStack.push(result);
            }
        }

        return tmpStack.pop();//最终结果
    }

    /**
     * 多位正整数运算
     * @param expression
     * @return
     * @throws Exception
     */
    public static double getResult2(String expression) throws Exception {
        if (!isVerified2(expression)) {
            throw new Exception("参数错误， 不是合法的表达式。");
        }
        //逆波兰表达式栈， 栈顶是第一个操作数
        Stack<Object> rpnStack = toRpn2(expression);
        //计算结果用临时栈
        Stack<Double> tmpStack = new Stack<>();

        while (!rpnStack.empty()) {

            if (rpnStack.peek() instanceof String) {//这个判断真费时间了。。。
                tmpStack.push(Double.parseDouble(rpnStack.pop().toString()));
            } else {
                Double second = tmpStack.pop();//先弹栈的是第二操作数
                Double first = tmpStack.pop();
                Double result = calculate(first, second, (char) rpnStack.pop());
                tmpStack.push(result);
            }
        }

        return tmpStack.pop();//最终结果
    }


    public static double getResult3(String expression) throws Exception {
        if (!isVerified3(expression)) {
            throw new Exception("参数错误， 不是合法的表达式。");
        }
        //逆波兰表达式栈， 栈顶是第一个操作数
        Stack<Object> rpnStack = toRpn3(expression);
        //计算结果用临时栈
        Stack<Double> tmpStack = new Stack<>();

        while (!rpnStack.empty()) {

            if (rpnStack.peek() instanceof String) {//这个判断真费时间了。。。
                tmpStack.push(Double.parseDouble(rpnStack.pop().toString()));
            } else {
                Double second = tmpStack.pop();//先弹栈的是第二操作数
                Double first = tmpStack.pop();
                Double result = calculate(first, second, (char) rpnStack.pop());
                tmpStack.push(result);
            }
        }

        return tmpStack.pop();//最终结果
    }

}
